<template>
  <div class="map-container">
    <div class="map" id="mapEchart" style="width:100%;height:100vh"></div>
    <div class="control-panel">
      <a class="btn btn-secondary dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
        诗人生平游历轨迹 
      </a>
      <ul class="dropdown-menu">
        <li @click="resetView()">重置视图</li>
        <li @click="flyTo('杜甫')">杜甫</li>
        <li @click="flyTo('李白')">李白</li>
        <li @click="flyTo('王维')">王维</li>
        <li @click="flyTo('李商隐')">李商隐</li>
        <li @click="flyTo('孟浩然')">孟浩然</li>
        <li @click="flyTo('韦应物')">韦应物</li>
        <li @click="flyTo('刘长卿')">刘长卿</li>
        <li @click="flyTo('杜牧')">杜牧</li>
        <li @click="flyTo('王昌龄')">王昌龄</li>
        <li @click="flyTo('李颀')">李颀</li>
      </ul>
    </div>
  </div>
</template>
 
<script setup>
import * as echarts from "echarts";
import "echarts-gl";
import { onMounted, ref } from "vue";
 
const myChart = ref(null);
const poetLocations = {
  '李白': { coord: [103.847, 31.689, 100], name: '碎叶城' },
  '杜甫': { coord: [113.467, 34.683, 100], name: '巩县' },
  '王维': { coord: [114.361, 34.787, 100], name: '祁县' },
  '李商隐': { coord: [113.005, 33.011, 100], name: '沁阳' },
  '孟浩然': { coord: [112.122, 32.009, 100], name: '襄阳' },
  '韦应物': { coord: [108.939, 34.341, 100], name: '长安' },
  '刘长卿': { coord: [116.407, 39.904, 100], name: '河间' },
  '杜牧': { coord: [108.939, 34.341, 100], name: '长安' },
  '王昌龄': { coord: [113.005, 33.011, 100], name: '沁阳' },
  '李颀': { coord: [113.467, 34.683, 100], name: '巩县' }
};
 
// 诗人游历路线数据 
const poetJourneys = {
  '李白': {
    birth: { coord: [103.847, 31.689, 100], name: '碎叶城', event: '李白出生地' },
    journey: [
      { coord: [108.939, 34.341, 100], name: '长安', event: '供奉翰林，写下《清平调》' },
      { coord: [116.407, 39.904, 100], name: '北京', event: '北游燕赵' },
      { coord: [120.155, 30.274, 100], name: '杭州', event: '写下《杭州送裴大泽》' },
      { coord: [117.283, 31.861, 100], name: '合肥', event: '游历江淮' },
      { coord: [115.892, 28.683, 100], name: '南昌', event: '写下《豫章行》' }
    ]
  },
  '杜甫': {
    birth: { coord: [113.467, 34.683, 100], name: '巩县', event: '杜甫出生地' },
    journey: [
      { coord: [108.939, 34.341, 100], name: '长安', event: '应试不第，困居十年' },
      { coord: [112.454, 34.683, 100], name: '洛阳', event: '与李白相识' },
      { coord: [104.066, 30.572, 100], name: '成都', event: '建草堂，写下《茅屋为秋风所破歌》' },
      { coord: [114.305, 30.593, 100], name: '武汉', event: '漂泊荆楚' },
      { coord: [113.005, 33.011, 100], name: '沁阳', event: '晚年定居' }
    ]
  },
  '王维': {
    birth: { coord: [114.361, 34.787, 100], name: '祁县', event: '王维出生地' },
    journey: [
      { coord: [108.939, 34.341, 100], name: '长安', event: '进士及第' },
      { coord: [112.454, 34.683, 100], name: '洛阳', event: '任太乐丞' },
      { coord: [119.412, 32.394, 100], name: '扬州', event: '游历江南' },
      { coord: [103.834, 36.061, 100], name: '兰州', event: '出使凉州' }
    ]
  }
};
 
// 唐朝重要城邦数据 
const tangDynastyCities = [
  { name: "长安", value: [108.939, 34.341, 200] }, // 今西安 
  { name: "洛阳", value: [112.454, 34.683, 180] },
  { name: "扬州", value: [119.412, 32.394, 150] },
  { name: "成都", value: [104.066, 30.572, 140] },
  { name: "广州", value: [113.264, 23.129, 130] },
  { name: "太原", value: [112.549, 37.857, 120] },
  { name: "荆州", value: [112.239, 30.335, 110] }
];
 
// 获取官方地理数据 
const getGeoJson = async (code) => {
  try {
    const res = await fetch(`https://geo.datav.aliyun.com/areas_v3/bound/${code}`); 
    return await res.json(); 
  } catch (error) {
    console.error(' 获取地理数据失败:', error);
    return null;
  }
};
 
// 生成路线数据 
const generateJourneyLines = (poetName) => {
  if (!poetJourneys[poetName]) return [];
  
  const journey = poetJourneys[poetName];
  const lines = [];
  
  // 从出生地到第一个游历地点 
  lines.push({ 
    coords: [
      journey.birth.coord, 
      journey.journey[0].coord  
    ]
  });
  
  // 连接所有游历地点 
  for (let i = 0; i < journey.journey.length  - 1; i++) {
    lines.push({ 
      coords: [
        journey.journey[i].coord, 
        journey.journey[i  + 1].coord 
      ]
    });
  }
  
  return lines;
};
 
// 生成游历地点数据 
const generateJourneyPoints = (poetName) => {
  if (!poetJourneys[poetName]) return [];
  
  const journey = poetJourneys[poetName];
  const points = [];
  
  // 添加出生地 
  points.push({ 
    name: journey.birth.name, 
    value: journey.birth.coord, 
    event: journey.birth.event, 
    itemStyle: { color: '#ff0000' },
     // 新增属性，标记为出生地 
     isBirthplace: true,
    // 默认只显示出生地标签 
    label: {
      show: true,
      formatter: params => {
        return `${params.data.name}\n${params.data.event}`; 
      },
      position: 'right',
      distance: 5,
      backgroundColor: 'rgba(255,255,255,0.9)',
      borderColor: '#666',
      borderWidth: 1,
      padding: [5, 10],
      borderRadius: 4,
      fontSize: 12,
      lineHeight: 18 
    }
  });
  
  // 添加游历地点 
  journey.journey.forEach((location,  index) => {
    points.push({ 
      name: location.name, 
      value: location.coord, 
      event: location.event, 
      itemStyle: { color: '#00ff00' },
      // 默认不显示标签，通过悬停显示 
      label: {
        show: false,
        formatter: params => {
          return `${params.data.name}\n${params.data.event}`; 
        },
        position: 'right',
        distance: 5,
        backgroundColor: 'rgba(255,255,255,0.9)',
        borderColor: '#666',
        borderWidth: 1,
        padding: [5, 10],
        borderRadius: 4,
        fontSize: 12,
        lineHeight: 18 
      },
      // 添加顺序标记 
      order: index
    });
  });
  
  return points;
};
 
// 飞向指定诗人并显示游历路线 
const flyTo = (poetName) => {
  if (!myChart.value  || !poetJourneys[poetName]) return;
 
  const option = myChart.value.getOption(); 
  
  // 更新视图控制 
  option.geo3D[0].viewControl  = {
    ...option.geo3D[0].viewControl, 
    center: [3, 10, 0],
    distance: 120,
    autoRotate: false 
  };
 
  // 添加路线系列 
  option.series  = option.series.filter(s  => s.name  !== '游历路线' && s.name  !== '游历地点');
  
  option.series.push({ 
    name: '游历路线',
    type: 'lines3D',
    coordinateSystem: 'geo3D',
    effect: {
      show: true,
      trailWidth: 2,
      trailLength: 0.2,
      trailOpacity: 0.6,
      trailColor: '#ffff00'
    },
    lineStyle: {
      width: 10,
      color: '#ff5500',
      opacity: 1 
    },
    effect: {
      show: true,
      trailWidth: 9,  // 加粗尾迹（原为2）
      trailLength: 0.9, // 加长尾迹（原为0.2）
      trailColor: '#ffcc00' // 更醒目的尾迹色 
    },
    data: generateJourneyLines(poetName)
  });

  const journeyPoints = generateJourneyPoints(poetName);
  
  option.series.push({ 
    name: '游历地点',
    type: 'scatter3D',
    coordinateSystem: 'geo3D',
    symbolSize: 15,
    label: {
      show: true,
      formatter: params => {
        return `${params.data.name}\n${params.data.event}`; 
      },
      position: 'right',
      distance: 5,
      backgroundColor: 'rgba(255,255,255,0.7)',
      padding: [5, 10],
      borderRadius: 4 ,
      fontSize: 12,
      lineHeight: 18 
    },
    itemStyle: {
      color: params => params.data.itemStyle.color  
    },
    emphasis: {
      label: {
        show: true // 悬停时显示标签 
      }
    },
    data: journeyPoints 
  });
 
  myChart.value.setOption(option); 
  
  // 高亮显示出生地 
  myChart.value.dispatchAction({ 
    type: 'highlight',
    seriesIndex: 0,
    name: poetLocations[poetName].name 
  });
  // 添加动画效果，逐个显示地点 
  let currentIndex = 0;
  const animatePoints = () => {
    if (currentIndex >= journeyPoints.length)  return;
    
    // 隐藏所有标签 
    const newOption = myChart.value.getOption(); 
    newOption.series.forEach(series  => {
      if (series.name  === '游历地点') {
        series.data.forEach(point  => {
          point.label  = point.label  || {};
          point.label.show  = false;
        });
      }
    });
    myChart.value.setOption(newOption); 
    
    // 显示当前点的标签 
    const pointOption = myChart.value.getOption(); 
    pointOption.series.forEach(series  => {
      if (series.name  === '游历地点') {
        series.data[currentIndex].label  = series.data[currentIndex].label  || {};
        series.data[currentIndex].label.show  = true;
      }
    });
    myChart.value.setOption(pointOption); 
    
    // 飞向当前点 
    const targetCoord = journeyPoints[currentIndex].value;
    const viewControl = {
      ...pointOption.geo3D[0].viewControl, 
      center: [targetCoord[0] - 108.939, targetCoord[1] - 34.341, 0],
      distance: 80 
    };
    
    myChart.value.setOption({ 
      geo3D: [{ viewControl }]
    });
    
    currentIndex++;
    setTimeout(animatePoints, 1000); // 2秒间隔 
  };
  
  // 开始动画 
  setTimeout(animatePoints, 1000);
};

 
// 重置视图 
const resetView = () => {
  if (!myChart.value)  return;
 
  const option = myChart.value.getOption(); 
  option.geo3D[0].viewControl  = {
    distance: 120,
    center: [3, 10, 0],
    autoRotate: false 
  };
  
  // 移除游历路线和地点 
  option.series  = option.series.filter(s  => s.name  !== '游历路线' && s.name  !== '游历地点');
  
  myChart.value.setOption(option); 
};
 
const initChart = async () => {
  const chinaGeoJson = await getGeoJson('100000_full.json'); 
  if (!chinaGeoJson) return;
 
  myChart.value  = echarts.init(document.getElementById("mapEchart")); 
  echarts.registerMap("china",  chinaGeoJson);
 
  const option = {
    tooltip: {
      show: true,
      formatter: params => {
        if (params.seriesType  === 'bar3D') {
          return `${params.name}<br/> 重要性: ${params.value[2]}`;  
        } else if (params.seriesType  === 'scatter3D') {
          // 诗人出生地提示信息 
          for (const poet in poetLocations) {
            if (poetLocations[poet].name === params.name)  {
              return `${poet}出生地: ${params.name}`; 
            }
          }
          // 游历地点提示信息 
          if (params.data.event)  {
            return `${params.name}<br/> 事件: ${params.data.event}`; 
          }
        }
        return params.name;  
      }
    },
    visualMap: {
      type: "continuous",
      calculable: true,
      max: 250,
      inRange: { color: ["#87aa66", "#eba438", "#d94d4c"] }
    },
    geo3D: {
      map: "china",
      roam: true,
      regionHeight: 2,
      itemStyle: {
        color: "#007aff",
        opacity: 0.8,
        borderWidth: 0.4,
        borderColor: "#000"
      },
      viewControl: {
        autoRotate: false,
        autoRotateAfterStill: 3,
        distance: 120,
        center: [3, 10, 0],
        minAlpha: 5,
        maxAlpha: 90,
        minBeta: -360,
        maxBeta: 360,
        animation: true,
        animationDurationUpdate: 1000,
        animationEasingUpdate: "cubicInOut"
      },
      emphasis: {
        label: {
          show: true,
          color: "#333",
          fontSize: 18 
        },
        itemStyle: {
          color: "#ff7aff"
        }
      },
      label: {
        show: true,
        position: "top",
        color: "#111",
        fontSize: 14,
        lineHeight: 16 
      },
      shading: "lambert",
      light: {
        main: {
          intensity: 1,
          shadow: true,
          shadowQuality: "medium",
          alpha: 55,
          beta: 10 
        },
        ambient: {
          intensity: 0.7 
        }
      }
    },
    series: [
      {
        name: "唐朝城邦",
        type: "bar3D",
        coordinateSystem: "geo3D",
        barSize: 1.5,
        shading: "lambert",
        opacity: 1,
        bevelSize: 0.2,
        label: {
          show: false,
          formatter: "{b}",
          position: "top",
          distance: 5 
        },
        emphasis: { // 鼠标悬停时显示标签 
          label: {
            show: true,
            formatter: "{b}",
            position: "top"
          }
        },
        data: tangDynastyCities 

      },
      {
        name: "诗人出生地",
        type: "scatter3D",
        coordinateSystem: "geo3D",
        symbolSize: 20,
        itemStyle: {
          color: '#ff0000'
        },
        label: {
          show: false,
          formatter: params => {
            for (const poet in poetLocations) {
              if (poetLocations[poet].name === params.name)  {
                return `${poet}出生地`;
              }
            }
            return params.name; 
          },
          position: "right"
        },
        emphasis: { // 鼠标悬停时显示标签 
          label: {
            show: true,
            formatter: params => {
              for (const poet in poetLocations) {
                if (poetLocations[poet].name === params.name)  {
                  return `${poet}出生地`;
                }
              }
              return params.name; 
            }
          }
        },
        data: Object.values(poetLocations).map(item  => ({
          name: item.name, 
          value: [...item.coord] 
        }))
      }
    ]
  };
 
  myChart.value.setOption(option); 
 
  window.addEventListener("resize",  () => {
    myChart.value.resize(); 
  });
};
onMounted(() => {
  initChart();
});
</script>
 
<style lang="less" scoped>
.map-container {
  width: 100%;
  height: 100vh;
  justify-content: center; /* 水平居中 */
  align-items: center; /* 垂直居中 */
 
  .control-panel {
    position: absolute;
    top: 20px;
    right: 800px;
    z-index: 100;
    display: flex;
    flex-direction: column;
    gap: 10px;


    button {
      padding: 8px 12px;
      background: rgba(255, 255, 255, 0.8);
      border: 1px solid #ddd;
      border-radius: 4px;
      cursor: pointer;
      transition: all 0.3s;
    }
  }
}
.btn{
  background: linear-gradient(to left, #9c373700, rgba(205, 11, 11, 0.6)); /* 从完全透明到60%不透明 */
}

</style>